using System;
using System.Collections;
using NFreeMarker.Ext.Beans;

namespace NFreeMarker.Template
{
    /// <summary>
    /// The default implementation of the ObjectWrapper
    /// interface.
    /// </summary>
    public class DefaultObjectWrapper : BeansWrapper
    {
        internal static readonly DefaultObjectWrapper Instance = new DefaultObjectWrapper();

        //static private Class W3C_DOM_NODE_CLASS, 
        //                     JYTHON_OBJ_CLASS;

        //static private ObjectWrapper JYTHON_WRAPPER;

        //static {
        //    try {
        //        W3C_DOM_NODE_CLASS = Class.forName("org.w3c.dom.Node");
        //    } catch (Exception e) {}
        //    try {
        //        JYTHON_OBJ_CLASS = Class.forName("org.python.core.PyObject");
        //        JYTHON_WRAPPER = freemarker.ext.jython.JythonWrapper.INSTANCE;
        //    } catch (Exception e) {}
        //}

        public override ITemplateModel Wrap(object obj)
        {
            if (obj == null)
            {
                return base.Wrap(null);
            }
            if (obj is ITemplateModel)
            {
                return (ITemplateModel) obj;
            }
            if (obj is string)
            {
                return new SimpleScalar((string) obj);
            }
            if (obj is byte)
            {
                return new SimpleNumber((byte) obj);
            }
            //TODO: if (obj is char)
            //{
            //    return new SimpleNumber((char) obj);
            //}
            if (obj is decimal)
            {
                return new SimpleNumber((decimal) obj);
            }
            if (obj is double)
            {
                return new SimpleNumber((double) obj);
            }
            if (obj is float)
            {
                return new SimpleNumber((float) obj);
            }
            if (obj is int)
            {
                return new SimpleNumber((int) obj);
            }
            if (obj is long)
            {
                return new SimpleNumber((long) obj);
            }
            if (obj is sbyte)
            {
                return new SimpleNumber((sbyte)obj);
            }
            if (obj is short)
            {
                return new SimpleNumber((short) obj);
            }
            if (obj is uint)
            {
                return new SimpleNumber((uint)obj);
            }
            if (obj is ulong)
            {
                return new SimpleNumber((ulong)obj);
            }
            if (obj is ushort)
            {
                return new SimpleNumber((ushort)obj);
            }
            //TODO: if (obj is Number) {
            //    return new SimpleNumber((Number) obj);
            //}
            if (obj is DateTimeOffset)
            {
                return new SimpleDate((DateTimeOffset) obj, GetDefaultDateType());
            }
            if (obj is IDictionary) {
                return new SimpleHash((IDictionary) obj, this);
            }
            if (obj is IEnumerable)
            {
                return new SimpleSequence((IEnumerable) obj, this);
            }
            if (obj is bool)
            {
                return (bool) obj ? TemplateBooleanModel.True : TemplateBooleanModel.False;
            }
            if (obj is IEnumerator)
            {
                return new SimpleCollection((IEnumerator) obj, this);
            }
            return HandleUnknownType(obj);
        }

        /**
         * Called if an unknown type is passed in.
         * Since 2.3, this falls back on XML wrapper and BeansWrapper functionality.
         */
        protected virtual ITemplateModel HandleUnknownType(object obj)
        {
            //TODO: if ((W3C_DOM_NODE_CLASS != null && W3C_DOM_NODE_CLASS.isInstance(obj)))
            //{
            //    return wrapDomNode(obj);
            //}
            //TODO: if (JYTHON_WRAPPER != null  && JYTHON_OBJ_CLASS.isInstance(obj)) {
            //    return JYTHON_WRAPPER.wrap(obj);
            //}
            return base.Wrap(obj); 
        }

        //public TemplateModel wrapDomNode(object obj) {
        //    return NodeModel.wrap((org.w3c.dom.Node) obj);
        //}
    }
}